Add color support for Windows consoles.
authorskeleten <skele@ymail.com>
Sun, 26 Jun 2016 13:03:08 +0000 (15:03 +0200)
committerskeleten <skele@ymail.com>
Tue, 28 Jun 2016 20:26:29 +0000 (22:26 +0200)
Fixes #2803

src/cargo/core/shell.rs
src/cargo/lib.rs
tests/shell.rs

index dbe854a09c69376471a09927c656e556156fdca4..b7996a36a1e2764ef2bd39872ac3349b139c05c7 100644 (file)
@@ -147,27 +147,57 @@ impl MultiShell {
 }
 
 impl Shell {
-    pub fn create(out: Box<Write + Send>, config: ShellConfig) -> Shell {
+    pub fn create<T: FnMut() -> Box<Write + Send>>(mut out_fn: T, config: ShellConfig) -> Shell {
+        let term = match Shell::get_term(out_fn()) {
+            Ok(t) => t,
+            Err(_) => NoColor(out_fn())
+        };
+
+        Shell {
+            terminal: term,
+            config: config,
+        }
+    }
+
+    #[cfg(any(windows))]
+    fn get_term(out: Box<Write + Send>) -> CargoResult<AdequateTerminal> {
+        // Check if the creation of a console will succeed
+        if ::term::WinConsole::new(vec![0u8; 0]).is_ok() {
+            let t = try!(::term::WinConsole::new(out));
+            if !t.supports_color() {
+                Ok(NoColor(Box::new(t)))
+            } else {
+                Ok(Colored(Box::new(t)))
+            }
+        } else {
+            // If we fail to get a windows console, we try to get a `TermInfo` one
+            Ok(Shell::get_terminfo_term(out))
+        }
+    }
+
+    #[cfg(any(unix))]
+    fn get_term(out: Box<Write + Send>) -> CargoResult<AdequateTerminal> {
+        Ok(Shell::get_terminfo_term(out))
+    }
+
+    fn get_terminfo_term(out: Box<Write + Send>) -> AdequateTerminal {
         // Use `TermInfo::from_env()` and `TerminfoTerminal::supports_color()`
         // to determine if creation of a TerminfoTerminal is possible regardless
         // of the tty status. --color options are parsed after Shell creation so
         // always try to create a terminal that supports color output. Fall back
         // to a no-color terminal regardless of whether or not a tty is present
         // and if color output is not possible.
-        Shell {
-            terminal: match ::term::terminfo::TermInfo::from_env() {
-                Ok(ti) => {
-                    let term = TerminfoTerminal::new_with_terminfo(out, ti);
-                    if !term.supports_color() {
-                        NoColor(term.into_inner())
-                    } else {
-                        // Color output is possible.
-                        Colored(Box::new(term))
-                    }
-                },
-                Err(_) => NoColor(out),
+        match ::term::terminfo::TermInfo::from_env() {
+            Ok(ti) => {
+                let term = TerminfoTerminal::new_with_terminfo(out, ti);
+                if !term.supports_color() {
+                    NoColor(term.into_inner())
+                } else {
+                    // Color output is possible.
+                    Colored(Box::new(term))
+                }
             },
-            config: config,
+            Err(_) => NoColor(out),
         }
     }
 
index 2db31fe7658b89befe7f1899f63f6bcd8a52c422..74608954877eba97d052b8db8deaf34382fa7d3f 100644 (file)
@@ -36,7 +36,7 @@ use core::shell::Verbosity::{Verbose};
 use core::shell::ColorConfig::{Auto};
 use term::color::{BLACK};
 
-pub use util::{CargoError, CliError, CliResult, human, Config, ChainError};
+pub use util::{CargoError, CargoResult, CliError, CliResult, human, Config, ChainError};
 
 macro_rules! bail {
     ($($fmt:tt)*) => (
@@ -137,16 +137,14 @@ pub fn shell(verbosity: Verbosity, color_config: ColorConfig) -> MultiShell {
     }
 
     let tty = isatty(Output::Stderr);
-    let stderr = Box::new(io::stderr());
 
     let config = ShellConfig { color_config: color_config, tty: tty };
-    let err = Shell::create(stderr, config);
+    let err = Shell::create(|| Box::new(io::stderr()), config);
 
     let tty = isatty(Output::Stdout);
-    let stdout = Box::new(io::stdout());
 
     let config = ShellConfig { color_config: color_config, tty: tty };
-    let out = Shell::create(stdout, config);
+    let out = Shell::create(|| Box::new(io::stdout()), config);
 
     return MultiShell::new(out, err, verbosity);
 
index 40471f0bf15e4efbd6297ec6a0db48b732db4ec0..549070d41573287a8ba4ef1217df28f9812639d3 100644 (file)
@@ -28,7 +28,7 @@ fn non_tty() {
     let config = ShellConfig { color_config: Auto, tty: false };
     let a = Arc::new(Mutex::new(Vec::new()));
 
-    Shell::create(Box::new(Sink(a.clone())), config).tap(|shell| {
+    Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| {
         shell.say("Hey Alex", color::RED).unwrap();
     });
     let buf = a.lock().unwrap().clone();
@@ -43,7 +43,7 @@ fn color_explicitly_disabled() {
     let config = ShellConfig { color_config: Never, tty: true };
     let a = Arc::new(Mutex::new(Vec::new()));
 
-    Shell::create(Box::new(Sink(a.clone())), config).tap(|shell| {
+    Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| {
         shell.say("Hey Alex", color::RED).unwrap();
     });
     let buf = a.lock().unwrap().clone();
@@ -58,7 +58,7 @@ fn colored_shell() {
     let config = ShellConfig { color_config: Auto, tty: true };
     let a = Arc::new(Mutex::new(Vec::new()));
 
-    Shell::create(Box::new(Sink(a.clone())), config).tap(|shell| {
+    Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| {
         shell.say("Hey Alex", color::RED).unwrap();
     });
     let buf = a.lock().unwrap().clone();
@@ -75,7 +75,7 @@ fn color_explicitly_enabled() {
     let config = ShellConfig { color_config: Always, tty: false };
     let a = Arc::new(Mutex::new(Vec::new()));
 
-    Shell::create(Box::new(Sink(a.clone())), config).tap(|shell| {
+    Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| {
         shell.say("Hey Alex", color::RED).unwrap();
     });
     let buf = a.lock().unwrap().clone();